﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Argos.Data;
using Argos.Windows.Forms;
using Argos.Data.Model;
using Argos;
using System.Workflow.Runtime;
using System.IO;
using ArgosDesktop.WorkflowServices;
using System.Workflow.Activities;
using Argos.Tracking;
using System.Workflow.Runtime.Tracking;
using System.Diagnostics;
using Argos.WorkflowServices;
using Argos.Workflows;
using Argos.Hosting;
using Argos.Diagnostics;

namespace ArgosDesktop
{
	public partial class Main : Form
	{

		public Main()
		{
			InitializeComponent();

			this.Targets.NewItem += this.Targets_NewItem;
			this.Targets.TargetDeleted += this.Targets_TargetDeleted;
			this.Targets.TargetModified += this.Targets_TargetModified;
			this.Targets.TargetOpened += this.Targets_TargetOpened;
			this.Targets.TargetsDeleting += this.Targets_TargetsDeleting;

			this.Text = this.ProductName;
			this.Size = MainSettings.Default.FormSize;

			this.aboutToolStripMenuItem.Text = string.Format(this.aboutToolStripMenuItem.Tag.ToString(), this.ProductName);
			this.MainNotifyArea.Text = this.ProductName;

			this.PreviousWindowState = FormWindowState.Normal;

			Program.EnsureAlertStorageFolder();
			this.AlertsWatcher.Path = UserSettings.Default.AlertStorageFolder;

			this.Targets.MonitoringRuntime = this.MonitoringRuntime;

			this.HandleCreated += delegate(object sender, EventArgs e)
			{
				this.WindowHandleCreated = true;
			};
		}


		
		private FormWindowState PreviousWindowState { get; set; }
		private bool WindowHandleCreated = false;


		#region private MonitoringRuntime MonitoringRuntime { get; }

		private MonitoringRuntime _MonitoringRuntime;

		private MonitoringRuntime MonitoringRuntime
		{
			get
			{
				if (null == _MonitoringRuntime)
				{
					Program.EnsurePersistenceStorageFolder();

					_MonitoringRuntime = new MonitoringRuntime(new AlertingService(), new TestExecutionService(), new StorageService());

					Action<int> setMonitoringWorkflowCountLabelHandler = delegate(int count)
					{
						if (this.WindowHandleCreated)
							this.RunningMonitoringWorkflowsLabel.Text = string.Format(this.RunningMonitoringWorkflowsLabel.Tag as string, count);
					};
					Action<int> setTestActivityCountLabelHandler = delegate(int count)
					{
						if (this.WindowHandleCreated)
							this.RunningTestActivitiesLabel.Text = string.Format(this.RunningTestActivitiesLabel.Tag as string, count);
					};

					_MonitoringRuntime.RunningMonitoringWorkflowCountChanged += delegate(object sender, EventArgs e)
					{
						if (this.WindowHandleCreated)
						{
							this.StatusBar.Invoke(setMonitoringWorkflowCountLabelHandler, _MonitoringRuntime.RunningMonitoringWorkflowCount);
							this.StatusBar.Invoke(setTestActivityCountLabelHandler, _MonitoringRuntime.RunningTestActivityCount);
						}
					};

					_MonitoringRuntime.RunningTestActivityCountChanged += delegate(object sender, EventArgs e)
					{
						if (this.WindowHandleCreated)
						{
							this.StatusBar.Invoke(setMonitoringWorkflowCountLabelHandler, _MonitoringRuntime.RunningMonitoringWorkflowCount);
							this.StatusBar.Invoke(setTestActivityCountLabelHandler, _MonitoringRuntime.RunningTestActivityCount);
						}
					};
				}
				return _MonitoringRuntime;
			}
		}

		#endregion



		protected override void OnClosing(CancelEventArgs e)
		{
			base.OnClosing(e);

			if (!e.Cancel)
			{
				if (this.WindowState == FormWindowState.Normal)
				{
					MainSettings.Default.FormSize = this.Size;
				}

				MainSettings.Default.Save();

				this.MonitoringRuntime.Dispose();
			}
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			this.WindowState = UserSettings.Default.StartMinimized ? FormWindowState.Minimized : FormWindowState.Normal;

			foreach (var id in Program.OpenTargets().ConvertAll<Guid>(t => t.Id))
			{
				this.StartTarget(id);
			}
		}

		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);

			if (this.WindowState != FormWindowState.Minimized)
			{
				this.ShowInTaskbar = true;
				this.PreviousWindowState = this.WindowState;
			}

			this.MainNotifyArea.Visible = (this.WindowState == FormWindowState.Minimized);
			if (this.MainNotifyArea.Visible)
			{
				this.ShowInTaskbar = false;
				this.MainNotifyArea.ShowBalloonTip(3000);
			}
		}



		private Alerts CurrentAlertDialog = null;
		private void ShowAlertDialog()
		{
			try
			{
				if (null == this.CurrentAlertDialog)
				{
					using (Alerts dlg = new Alerts())
					{
						this.CurrentAlertDialog = dlg;
						dlg.ShowDialog(this);
					}
				}
				else
				{
					this.CurrentAlertDialog.RefreshAlerts();
				}
			}
			finally
			{
				this.CurrentAlertDialog = null;
			}
		}

		private void StartTarget(Guid targetId)
		{
			Target target = Program.OpenTarget(targetId);
			
			if (!this.Targets.Items.Contains(target))
			{
				this.Targets.Items.Add(target);
			}

			if (null != target)
			{
				object state = Program.GetTestState(targetId);
				this.MonitoringRuntime.AddTarget(target, state);
			}
		}



		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.Close();
			Application.Exit();
		}

		private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
		{
			using (AboutBox dlg = new AboutBox())
			{
				dlg.ShowDialog(this);
			}
		}

		private void MainNotifyArea_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			this.WindowState = this.PreviousWindowState;
		}

		private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			using (Argos.Windows.Forms.PropertyEditorDialog dlg = new Argos.Windows.Forms.PropertyEditorDialog(UserSettings.Default))
			{
				dlg.Text = "Options";

				DialogResult result = dlg.ShowDialog(this);
				if (result == DialogResult.OK)
				{
					UserSettings.Default.Save();
					if (UserSettings.Default.EnableLogging)
					{
						Program.EnableTracing();
						Tracer.TraceData(TraceEventType.Verbose, 0, "Logging was enabled.");
					}
					else
					{
						Tracer.TraceData(TraceEventType.Verbose, 0, "Logging is disabled.");
						Program.DisableTracing();
					}
				}
				else
				{
					UserSettings.Default.Reload();
				}
			}
		}

		private void targetToolStripMenuItem_Click(object sender, EventArgs e)
		{
			try
			{
				using(TargetEditorDialog dlg = new TargetEditorDialog(this.MonitoringRuntime.WorkflowRuntime))
				{
					dlg.Text = "Create new Target";
					dlg.SelectedTarget = new Target() { Name = "<New Target>" };
					dlg.SelectedTarget.Test.ExecutionTimeout = TimeSpan.FromMilliseconds(5000);
					
					if (dlg.ShowDialog(this) == DialogResult.OK)
					{
						Program.SaveTarget(dlg.SelectedTarget);
						this.Targets.Items.Add(dlg.SelectedTarget);
						this.StartTarget(dlg.SelectedTarget.Id);
					}
				}
			}
			catch (Exception ex)
			{
				Program.ShowException(this, "An exception occured while creating a new target.", ex);
			}

		}

		private void Targets_TargetOpened(object sender, ItemEventArgs<Target> e)
		{
			using (TargetEditorDialog dlg = new TargetEditorDialog(this.MonitoringRuntime.WorkflowRuntime))
			{
				int i = this.Targets.Items.IndexOf(e.Item);

				dlg.Text = "Edit Target";
				dlg.SelectedTarget = (Target)e.Item.Clone();

				if (dlg.ShowDialog(this) == DialogResult.OK)
				{
					this.Targets.Items[i] = dlg.SelectedTarget;
				}
			}
		}

		private void Targets_TargetDeleted(object sender, ItemEventArgs<Target> e)
		{
			this.MonitoringRuntime.RemoveTarget(e.Item.Id);
			Program.DeleteTarget(e.Item);
		}

		private void Targets_TargetModified(object sender, ItemEventArgs<Target> e)
		{
			Program.SaveTarget(e.Item);
		}

		private void Targets_NewItem(object sender, EventArgs e)
		{
			this.targetToolStripMenuItem.PerformClick();
		}

		private void Targets_TargetsDeleting(object sender, CancelEventArgs e)
		{
			if (MessageBox.Show(this, "Are you sure you want to delete the selected targets? This action cannot be undone.", "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
			{
				e.Cancel = true;
			}
		}

		private void argosOnTheWebToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Process.Start("http://www.codeplex.com/Argos");
		}

		private void AlertsWatcher_Changed(object sender, FileSystemEventArgs e)
		{
			System.Diagnostics.Debug.WriteLine(string.Format("{0} - New alerts available at '{1}'", DateTime.Now, e.FullPath));
			this.NewAlertsNotifyIcon.Visible = true;
			this.NewAlertsNotifyIcon.ShowBalloonTip(5000);
		}

		private void NewAlertsNotifyIcon_BalloonTipClicked(object sender, EventArgs e)
		{
			this.NewAlertsNotifyIcon.Visible = false;
			this.ShowAlertDialog();
		}

		private void NewAlertsNotifyIcon_DoubleClick(object sender, EventArgs e)
		{
			this.NewAlertsNotifyIcon.Visible = false;
			this.ShowAlertDialog();
		}

		private void alertsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.NewAlertsNotifyIcon.Visible = false;
			this.ShowAlertDialog();
		}

		private void logsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (!string.IsNullOrEmpty(UserSettings.Default.LogFolderPath))
			{
				if (Directory.Exists(UserSettings.Default.LogFolderPath))
				{
					Process.Start(UserSettings.Default.LogFolderPath);
				}
				else
				{
					MessageBox.Show(this, string.Format("The folder configured for logging ('{0}') does not exist.", UserSettings.Default.LogFolderPath), "No Folder", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				}
			}
		}

	}
}
